package com.garyme.hycloud.service.impl;

import com.garyme.hycloud.model.HyFile;
import com.garyme.hycloud.model.HyFileBase;
import com.garyme.hycloud.service.IFileDirObserverService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;


@Service
public class FileDirObserverServiceImpl implements IFileDirObserverService {


    @Override
    public HyFileBase listFileBase(String basePath,String path) {
        HyFileBase  hfb = new HyFileBase();
        List<HyFile> list;
        list = listFiles(basePath,path);
        hfb.setFileList(list);
        hfb.setTotal(list.size());
        hfb.setCurrentPath(path);
        return hfb;
    }

    @Override
    public List<HyFile> listFiles(String basePath,String dir) {
        File path = new File(basePath +  dir);
        File[] files;
        List<HyFile> fileList = new ArrayList<>();
        if(path.exists() && path.isDirectory()){
            if((files=path.listFiles())!= null){
                for(File file : files){
                    if( file.getName().equals("hiberfil.sys") || file.getName().equals("swapfile.sys") || file.getName().equals("pagefile.sys") || file.getName().equals("System Volume Information")){
                        continue;
                    }
                    HyFile hyFile = getHyFile(dir,file,getFileType(file));
                    fileList.add(hyFile);
                }
                fileList.sort((t1, t2) -> t2.getIsDir().compareTo(t1.getIsDir()));

                return fileList;
            }
        }

        return fileList;
    }

    private static HyFile getHyFile(String dir,File file,String type) {
        if(dir.equals("/"))
            dir="";
        HyFile hyFile = new HyFile();
        hyFile.setFileName(file.getName());
        hyFile.setFileType(type);
        hyFile.setFileUrl(dir + "/" +  file.getName());
        hyFile.setFileSize(file.length());
        hyFile.setIsDir(file.isDirectory());
        hyFile.setAbsPath(dir + "/" + file.getName());
        hyFile.setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(file.lastModified()), ZoneId.systemDefault()));
        return hyFile;
    }


//    private static HyFile getHyFile(File file,String basePath){
//        return getHyFile(file,getFileType(file));
//    }
    private static String getFileType(File file){
        if(file.isDirectory()){
            return "dir";
        }else{
            if(!file.getName().contains("."))
                return "file";
            return file.getName().toLowerCase().substring(file.getName().lastIndexOf(".")+1);
        }
    }
    @Override
    public boolean delFileByName(String basePath,String name) {

        File file = new File(basePath+name);
        if(file.isFile()) return file.delete();
        deleteFileDir(file);
        return file.delete();
    }


    private static boolean deleteFileDir(File file) {
        try{
            File[] files = file.listFiles();
            if (files!=null){//如果包含文件进行删除操作
                for (int i = 0; i < files.length ; i++) {
                    if (files[i].isFile()){
                        //删除子文件
                        files[i].delete();
                    }else if (files[i].isDirectory()){
                        //通过递归的方法找到子目录的文件
                        deleteFileDir(files[i]);
                    }
                    files[i].delete();//删除子目录
                }
            }else{
                file.delete();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return true;
    }


    @Override
    public boolean renameFile(String basePath,String oldName, String newName) {

        File file = new File(basePath+oldName);
        return file.renameTo(new File(basePath+newName));
    }

    @Override
    public boolean copyFile(String basePath, String oldName, String newName) {

        File source = new File(basePath+oldName);
        File target = new File(basePath+newName);
        if(source.isFile() && target.isDirectory()){
            copyFile(source,new File(basePath+newName+"/"+source.getName()));
        }else if(source.isDirectory()){
            copyDirectory(source,basePath+newName+"/"+source.getName());
        }

        return true;
    }
    private static void copyDirectory(File directory, String newName) {
        File targetDirectory = new File(newName);
        if(!targetDirectory.exists()){
            targetDirectory.mkdir();
        }
        File[] files = directory.listFiles();
        for(File file : files){
            if(file.isDirectory()){
                File newDir = new File(newName+"/"+file.getName());
                if(!newDir.exists())
                    newDir.mkdir();
                copyDirectory(file,newName+"/"+file.getName());
            }else{
                try{
                    copyFile(file,new File(newName+"/"+file.getName()));
                }catch(Exception e){

                }
            }
        }

    }
    private static void copyFile(File in,File out){
        try{
            BufferedInputStream in1 = new BufferedInputStream(new FileInputStream(in));
            BufferedOutputStream out1 = new BufferedOutputStream(new FileOutputStream(out));
            byte[] b = new byte[1024];
            int temp = 0;
            while((temp = in1.read(b))!= -1){
                out1.write(b,0,temp);
            }
            out1.close();
            in1.close();
        }catch (Exception e){
        }
    }
    @Override
    public boolean moveFile(String basePath, String oldName, String newName) {
        File f1 = new File(basePath+oldName);
        File f2 = new File(basePath+newName+"/"+oldName.substring(oldName.lastIndexOf("/")));

        return f1.renameTo(f2);
    }

    @Override
    public boolean newDir(String basePath, String name, String path) {
        File f = new File(basePath+"/"+path + "/" + name);
        return f.mkdir();
    }

    @Override
    public boolean chunkFile(MultipartFile file, String path, Integer chunkIdx, Integer chunkTotal, String fileName) {
        try {
            file.transferTo(new File(path + fileName+ "."+chunkTotal+ "-"+chunkIdx+".part"));
        }catch(Exception e){
            return false;
        }

        return true;
    }

    @Override
    public boolean uploadFile(MultipartFile file, String path, String fileName) {

        String orginFileName = file.getOriginalFilename();
        File targetFile = new File(path+orginFileName);
        try{
            file.transferTo(targetFile);
        }catch(Exception e){
            return false;
        }

        return true;
    }

    @Override
    public boolean mergeFiles(String basePath, String fileName, Integer chunkTotal) {
        try{
            for (int i = 0; i < chunkTotal; i++){
                File file = new File(basePath +fileName+"."+chunkTotal+"-"+i+".part");
                File targetFile = new File(basePath +fileName);
                FileOutputStream out = new FileOutputStream(targetFile,true);
                FileInputStream in = new FileInputStream(file);
                byte[] buffer = new byte[1024];
                int len = 0;
                while ((len = in.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }
                in.close();
                out.close();

                if(file.exists()){
                    file.delete();
                }
            }
        }catch (Exception e){
            return false;
        }

        return true;
    }

//    @Override
//    public CompletableFuture<HyFile> calcFileHashBackground(File file) {
//        String fileHash = null;
//        try{
//            fileHash = MD5.asHex(MD5.getHash(file));
//            redisTemplate.opsForValue().setIfAbsent(fileHash,file);
//        }catch(Exception e){
//
//        }
//        return null;
//    }


//    @Override
//    public List<HyFile> queryAllDisk() {
//        //查询所有磁盘分区
//            File[] roots = File.listRoots();
//            List<HyFile> fileList = new ArrayList<>();
//            for(File root : roots){
//                fileList.add(getHyFile(root,"disk"));
//            }
//        return fileList;
//    }
}
